package com.hellobike.haxing.modules.wms.facade.impl;

import com.alibaba.fastjson.JSON;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hellobike.haxing.modules.product.entity.Sku;
import com.hellobike.haxing.modules.product.entity.Spu;
import com.hellobike.haxing.modules.product.service.ISkuService;
import com.hellobike.haxing.modules.product.service.ISpuService;
import com.hellobike.haxing.modules.wms.constans.WmsConstans;
import com.hellobike.haxing.modules.wms.dto.DeliveryOrderHeaderDto;
import com.hellobike.haxing.modules.wms.dto.PickTaskDto;
import com.hellobike.haxing.modules.wms.dto.StockChangeDto;
import com.hellobike.haxing.modules.wms.entity.*;
import com.hellobike.haxing.modules.wms.enums.*;
import com.hellobike.haxing.modules.wms.exception.WmsServiceException;
import com.hellobike.haxing.modules.wms.facade.WmsDeliveryFacade;
import com.hellobike.haxing.modules.wms.facade.WmsStockFacade;
import com.hellobike.haxing.modules.wms.service.*;
import com.hellobike.haxing.modules.wms.utils.ListUtil;
import com.hellobike.haxing.modules.wms.utils.WmsCodeGeneratorUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.math.BigDecimal;
import java.util.*;
import java.util.stream.Collectors;

@Component("wmsDeliveryFacade")
@Slf4j
public class WmsDeliveryFacadeImpl implements WmsDeliveryFacade {

    @Autowired
    private IDeliveryOrderHeaderService deliveryOrderHeaderService;
    @Autowired
    private IDeliveryOrderDetailService deliveryOrderDetailService;
    @Autowired
    private IWaveService waveService;
    @Autowired
    private ISkuService skuService;
    @Autowired
    private ISpuService spuService;
    @Autowired
    private IPickHeaderService pickHeaderService;
    @Autowired
    private IPickTaskService pickTaskService;
    @Autowired
    private ISkuExtService skuExtService;
    @Autowired
    private IStockBatchLocService stockBatchLocService;
    @Autowired
    private WmsStockFacade wmsStockFacade;
    @Autowired
    private IContainerService containerService;
    @Autowired
    private ICodeHolderPointService codeHolderPointService;
    @Autowired
    private IDeliveryOrderBoxService deliveryOrderBoxService;

    @Autowired
    private ILocationService locationService;
    @Autowired
    private IStockPickService stockPickService;


    @Transactional(rollbackFor = Exception.class)
    @Override
    public DeliveryOrderHeader createDeliveryOrder(DeliveryOrderHeader header, List<DeliveryOrderDetail> details, Long warehouseId, Integer userId) throws WmsServiceException {
        if (header == null) {
            throw new WmsServiceException("header不能为空");
        }
        if (ListUtil.isNullOrEmpty(details)) {
            throw new WmsServiceException("detail不能为空");
        }
        header.setOrderCode(WmsCodeGeneratorUtil.createDeliveryOrderCode(warehouseId));
        header.setWarehouseId(warehouseId);
        header.setOrderStatus(DeliveryOrderStatusEnum.INIT.getValue());
        header.setOrderType(DeliveryOrderTypeEnum.SHOP.getValue());
        if (!deliveryOrderHeaderService.save(header)) {
            throw new WmsServiceException("保存出库单异常");
        }
        for (DeliveryOrderDetail detail : details) {
            detail.setOrderHeaderId(header.getId());
            detail.setOrderHeaderCode(header.getOrderCode());
            detail.setWarehouseId(warehouseId);
            detail.setShopId(header.getShopId());
            detail.setUserId(Long.valueOf(userId));
        }
        if (!deliveryOrderDetailService.saveBatch(details)) {
            throw new WmsServiceException("保存出库单明细异常");
        }
        return header;
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void createWave(List<Long> deliveryHeaderIds, Long warehouseId, Integer userId) throws WmsServiceException {
        if (ListUtil.isNullOrEmpty(deliveryHeaderIds)) {
            throw new WmsServiceException("发货单ID参数缺失");
        }
        Wave wave = new Wave();
        wave.setWarehouseId(warehouseId);
        wave.setWaveCode(WmsCodeGeneratorUtil.createWaveCode(warehouseId));
        wave.setWaveType(WaveTypeEnum.ZTD.getValue());
        wave.setWaveStatus(WaveStatusEnum.INIT.getValue());
        if (!waveService.save(wave)) {
            throw new WmsServiceException("生成波次异常");
        }
        for (Long deliveryHeaderId : deliveryHeaderIds) {
            DeliveryOrderHeader orderHeader = deliveryOrderHeaderService.getById(deliveryHeaderId);
            if (orderHeader == null) {
                throw new WmsServiceException("订单不存在:" + deliveryHeaderId);
            }
            if (!DeliveryOrderStatusEnum.INIT.getValue().equals(orderHeader.getOrderStatus())) {
                throw new WmsServiceException("订单不是初始化：" + orderHeader.getOrderCode());
            }
            if (orderHeader.getWaveId() != null || orderHeader.getWaveCode() != null) {
                throw new WmsServiceException("订单已绑定波次：" + orderHeader.getWaveCode());
            }
            orderHeader.setWaveId(wave.getId());
            orderHeader.setWaveCode(wave.getWaveCode());
            orderHeader.setWaveFlag(1);
            if (!deliveryOrderHeaderService.updateById(orderHeader)) {
                throw new WmsServiceException("绑定波次异常");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void batchCreateWavePickTask(List<Long> waveIds, Long warehouseId, Integer userId) throws WmsServiceException {
        if (ListUtil.isNullOrEmpty(waveIds)) {
            throw new WmsServiceException("参数缺失");
        }
        for (Long waveId : waveIds) {
            createWavePickTask(waveId, warehouseId, userId);
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void createWavePickTask(Long waveId, Long warehouseId, Integer userId) throws WmsServiceException {
        if (waveId == null) {
            throw new WmsServiceException("waveId参数缺失");
        }
        Wave wave = waveService.getById(waveId);
        if (wave == null) {
            throw new WmsServiceException("波次不存在");
        }
        if (!WaveStatusEnum.INIT.getValue().equals(wave.getWaveStatus())) {
            throw new WmsServiceException("波次状态不是初始化");
        }
        List<DeliveryOrderHeader> deliveryOrderHeaders = deliveryOrderHeaderService.getByWaveId(waveId);
        if (ListUtil.isNullOrEmpty(deliveryOrderHeaders)) {
            throw new WmsServiceException("该波次下未找到订单信息");
        }
        //汇总商品信息，生成波次拣货任务
        List<DeliveryOrderDetail> lcDetails = new ArrayList<>();//冷藏
        List<DeliveryOrderDetail> ldDetails = new ArrayList<>();//冷冻
        List<DeliveryOrderDetail> cwDetails = new ArrayList<>();//常温
        for (DeliveryOrderHeader header : deliveryOrderHeaders) {
            List<DeliveryOrderDetail> details = deliveryOrderDetailService.getByHeaderId(header.getId());
            if (ListUtil.isNullOrEmpty(details)) {
                throw new WmsServiceException("订单明细不存在:" + header.getOrderCode());
            }
            for (DeliveryOrderDetail detail : details) {
                Spu spu = spuService.getById(detail.getProductId());
                //存储类型：1-常温、2-冷藏、3-冷冻
                Integer storeType = 1;
                try {
                    storeType = spu.getStoreType();
                } catch (Exception ex) {
                    ex.printStackTrace();
                    log.error("product:" + JSON.toJSONString(detail));
                }
                if (storeType == null) {
                    storeType = 1;
                }
                if (1 == storeType) {
                    cwDetails.add(detail);
                } else if (2 == storeType) {
                    lcDetails.add(detail);
                } else if (3 == storeType) {
                    ldDetails.add(detail);
                }
            }
        }
        if (ListUtil.isNotEmpty(lcDetails)) {
            generatorWavePickTask(waveId, warehouseId, wave, lcDetails, PickTypeEnum.KQ, "冷藏");
        }
        if (ListUtil.isNotEmpty(ldDetails)) {
            generatorWavePickTask(waveId, warehouseId, wave, ldDetails, PickTypeEnum.KQ, "冷冻");
        }
        if (ListUtil.isNotEmpty(cwDetails)) {
            generatorWavePickTask(waveId, warehouseId, wave, cwDetails, PickTypeEnum.KQ, "常温");
        }
        //更新波次状态
        wave.setWaveStatus(WaveStatusEnum.PUBLISH.getValue());
        if (!waveService.updateById(wave)) {
            throw new WmsServiceException("更新波次状态异常");
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void batchCreateDOPickTask(List<Long> deliveryHeaderIds, Long warehouseId, Integer userId) throws WmsServiceException {
        if (ListUtil.isNullOrEmpty(deliveryHeaderIds)) {
            throw new WmsServiceException("参数缺失");
        }
        for (Long deliveryHeaderId : deliveryHeaderIds) {
            createDOPickTask(deliveryHeaderId, warehouseId, userId);
        }
    }

    private void generatorWavePickTask(Long waveId, Long warehouseId, Wave wave, List<DeliveryOrderDetail> lcDetails, PickTypeEnum pickTypeEnum, String sotreType) throws WmsServiceException {
        PickHeader pickHeader = new PickHeader();
        pickHeader.setDocId(waveId);
        pickHeader.setDocNo(wave.getWaveCode());
        pickHeader.setDocType(DocTypeEnum.WV.getValue());
        pickHeader.setWarehouseId(wave.getWarehouseId());
        pickHeader.setPickType(pickTypeEnum.getValue());
        pickHeader.setPickStatus(PickStatusEnum.PUBLISHED.getValue());
        pickHeader.setPickCode(WmsCodeGeneratorUtil.createPickCode(warehouseId));
        pickHeader.setStoreType(sotreType);
        if (!pickHeaderService.save(pickHeader)) {
            throw new WmsServiceException("生成拣货单异常");
        }
        Map<Long, Integer> skuCountMap = new HashMap<>();
        for (DeliveryOrderDetail detail : lcDetails) {
            skuCountMap.merge(detail.getSkuId(), detail.getPlanQty(), (a, b) -> a + b);
        }
        for (Map.Entry<Long, Integer> entry : skuCountMap.entrySet()) {
            PickTask task = new PickTask();
            task.setTaskNo(WmsCodeGeneratorUtil.createTaskCode(warehouseId));
            task.setTaskType(StockTaskTypeEnum.PK.getValue());
            task.setTaskStatus(StockTaskStatusEnum.PUBLISHED.getValue());
//            task.setBatchId(WmsConstans.DEF_BATCH_ID);
            task.setDamaged(0);
            task.setDocId(waveId);
            task.setDocLineId(waveId);
            task.setDocNo(wave.getWaveCode());
            task.setDocType(DocTypeEnum.WV.getValue());
            task.setDocOperId(pickHeader.getId());
            task.setDocOperNo(pickHeader.getPickCode());
            task.setFmLocId(skuExtService.getDefSkuLocId(entry.getKey(), warehouseId));
            task.setPlanLocId(WmsConstans.DEF_PICK_LOC_ID);
            task.setQty(BigDecimal.valueOf(entry.getValue()));
            task.setSkuId(entry.getKey());
            task.setWarehouseId(warehouseId);
            if (!pickTaskService.save(task)) {
                throw new WmsServiceException("生成拣货任务异常");
            }
        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void createDOPickTask(Long deliveryHeaderId, Long warehouseId, Integer userId) throws WmsServiceException {
        if (deliveryHeaderId == null) {
            throw new WmsServiceException("订单ID参数缺失");
        }
        DeliveryOrderHeader orderHeader = deliveryOrderHeaderService.getById(deliveryHeaderId);
        if (orderHeader == null) {
            throw new WmsServiceException("订单不存在");
        }
        if (!DeliveryOrderStatusEnum.INIT.getValue().equals(orderHeader.getOrderStatus())) {
            throw new WmsServiceException("订单不是初始化");
        }
        if (pickHeaderService.hasPick(deliveryHeaderId, DocTypeEnum.DO.getValue())) {
            throw new WmsServiceException("订单已有拣货单生成");
        }
        List<DeliveryOrderDetail> details = deliveryOrderDetailService.getByHeaderId(deliveryHeaderId);
        if (ListUtil.isNullOrEmpty(details)) {
            throw new WmsServiceException("订单明细不存在:" + orderHeader.getOrderCode());
        }
        PickHeader pickHeader = new PickHeader();
        pickHeader.setDocId(deliveryHeaderId);
        pickHeader.setDocNo(orderHeader.getOrderCode());
        pickHeader.setDocType(DocTypeEnum.DO.getValue());
        pickHeader.setWarehouseId(orderHeader.getWarehouseId());
        pickHeader.setPickType(PickTypeEnum.ZTD.getValue());
        pickHeader.setPickStatus(PickStatusEnum.PUBLISHED.getValue());
        pickHeader.setPickCode(WmsCodeGeneratorUtil.createPickCode(warehouseId));
        if (!pickHeaderService.save(pickHeader)) {
            throw new WmsServiceException("生成拣货单异常");
        }
        for (DeliveryOrderDetail detail : details) {
            PickTask task = new PickTask();
            task.setTaskNo(WmsCodeGeneratorUtil.createTaskCode(warehouseId));
            task.setTaskType(StockTaskTypeEnum.PK.getValue());
            task.setTaskStatus(StockTaskStatusEnum.PUBLISHED.getValue());
//            task.setBatchId(WmsConstans.DEF_BATCH_ID);
            task.setDamaged(0);
            task.setDocId(deliveryHeaderId);
            task.setDocLineId(detail.getId());
            task.setDocNo(orderHeader.getOrderCode());
            task.setDocType(DocTypeEnum.DO.getValue());
            task.setDocOperId(pickHeader.getId());
            task.setDocOperNo(pickHeader.getPickCode());
            task.setFmLocId(skuExtService.getDefSkuLocId(detail.getSkuId(), warehouseId));
            task.setPlanLocId(WmsConstans.DEF_PICK_LOC_ID);
            task.setQty(BigDecimal.valueOf(detail.getPlanQty()));
            task.setSkuId(detail.getSkuId());
            task.setWarehouseId(warehouseId);
            if (!pickTaskService.save(task)) {
                throw new WmsServiceException("生成拣货任务异常");
            }
        }
        //回写DO
        orderHeader.setPickId(pickHeader.getId());
        orderHeader.setPickCode(pickHeader.getPickCode());
        orderHeader.setPickFlag(1);
        if (!deliveryOrderHeaderService.updateById(orderHeader)) {
            throw new WmsServiceException("绑定拣货单异常");
        }

    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void pickWavePickTask(List<PickTask> tasks, Long pickHeaderId, String opName, Long warehouseId, Integer userId) throws WmsServiceException {
        if (ListUtil.isNullOrEmpty(tasks)) {
            throw new WmsServiceException("任务参数缺失");
        }
        PickHeader pickHeader = pickHeaderService.getById(pickHeaderId);
        if (pickHeader == null) {
            throw new WmsServiceException("拣货单不存在");
        }
        if (!pickHeader.getDocType().equals(DocTypeEnum.WV.getValue())) {
            throw new WmsServiceException("拣货单类型不是波次");
        }
        if (!pickHeader.getPickStatus().equals(PickStatusEnum.PUBLISHED.getValue())) {
            throw new WmsServiceException("拣货单状态异常");
        }
        Wave wave = waveService.getById(pickHeader.getDocId());
        if (wave == null) {
            throw new WmsServiceException("波次不存在");
        }
        if (!wave.getWaveStatus().equals(WaveStatusEnum.PUBLISH.getValue())) {
            throw new WmsServiceException("波次状态异常");
        }
        Map<Long, PickTask> pickTaskMap = tasks.stream().collect(Collectors.toMap(PickTask::getId, v -> v));
        List<PickTask> pickTasks = pickTaskService.getByDocOperId(pickHeader.getId());
        pickTasks.sort(Comparator.comparing(PickTask::getSkuId));
        for (PickTask pickTask : pickTasks) {
            PickTask param = pickTaskMap.get(pickTask.getId());
            if (param == null) {
                throw new WmsServiceException("任务参数缺失");
            }
            if (!param.getTaskStatus().equals(StockTaskStatusEnum.PUBLISHED.getValue())) {
                throw new WmsServiceException("任务状态异常" + param.getId());
            }
            BigDecimal needSubQty = param.getPickQty();
            if (needSubQty.compareTo(BigDecimal.ZERO) < 0) {
                throw new WmsServiceException("拣货数不能为负数");
            }
            if (needSubQty.compareTo(BigDecimal.ZERO) > 0) {
                Sku sku = skuService.getByIdForReal(pickTask.getSkuId());
                if (sku == null) {
                    sku = new Sku();
                    sku.setId(pickTask.getSkuId());
                    sku.setBarcode("none-" + pickTask.getSkuId());
                    sku.setSkuCode("none-" + pickTask.getSkuId());
                }
                //查询可用的主库存
                List<StockBatchLoc> stockBatchLocs = stockBatchLocService.queryStockBySkuIdAndWarehouseId(pickTask.getSkuId(), warehouseId);
                if (ListUtil.isNullOrEmpty(stockBatchLocs)) {
                    throw new WmsServiceException("主库存未找到该商品:商品编码:" + sku.getSkuCode() + "商品编条码:" + sku.getBarcode());
                }
                BigDecimal totalQty = stockBatchLocs.stream().map(StockBatchLoc::getAvailableQty).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
                if (totalQty.compareTo(needSubQty) < 0) {
                    throw new WmsServiceException("库存不足：商品编码:" + sku.getSkuCode() + "商品编条码:" + sku.getBarcode());
                }
                for (StockBatchLoc stockBatchLoc : stockBatchLocs) {
                    if (needSubQty.compareTo(BigDecimal.ZERO) == 0) {//扣减结束
                        break;
                    }
                    if (stockBatchLoc.getAvailableQty().compareTo(needSubQty) >= 0) {
                        //扣减主库存
                        StockChangeDto stockChangeDto = new StockChangeDto();
                        stockChangeDto.setSkuId(pickTask.getSkuId());
                        stockChangeDto.setBatchId(stockBatchLoc.getBatchId());
//                    stockChangeDto.setToBatchId(WmsConstans.DEF_BATCH_ID);
                        stockChangeDto.setQty(needSubQty);
                        stockChangeDto.setLocId(stockBatchLoc.getLocId());
                        stockChangeDto.setToLocId(pickTask.getToLocId());
                        stockChangeDto.setWarehouseId(warehouseId);
                        stockChangeDto.setIsDamaged(pickTask.getDamaged());
                        stockChangeDto.setDocId(pickTask.getDocId());
                        stockChangeDto.setDocNo(pickTask.getDocNo());
                        stockChangeDto.setDocLineId(pickTask.getDocLineId());
                        stockChangeDto.setUserId(userId);
                        stockChangeDto.setStockId(stockBatchLoc.getId());
                        stockChangeDto = wmsStockFacade.subMainStock(stockChangeDto);
                        //增加拣货暂存库存
                        stockChangeDto = wmsStockFacade.addPickStock(stockChangeDto);
                        needSubQty = BigDecimal.ZERO;
                    } else {
                        //扣减主库存
                        StockChangeDto stockChangeDto = new StockChangeDto();
                        stockChangeDto.setSkuId(pickTask.getSkuId());
                        stockChangeDto.setBatchId(stockBatchLoc.getBatchId());
//                    stockChangeDto.setToBatchId(WmsConstans.DEF_BATCH_ID);
                        stockChangeDto.setQty(stockBatchLoc.getAvailableQty());
                        stockChangeDto.setLocId(stockBatchLoc.getLocId());
                        stockChangeDto.setToLocId(pickTask.getToLocId());
                        stockChangeDto.setWarehouseId(warehouseId);
                        stockChangeDto.setIsDamaged(pickTask.getDamaged());
                        stockChangeDto.setDocId(pickTask.getDocId());
                        stockChangeDto.setDocNo(pickTask.getDocNo());
                        stockChangeDto.setDocLineId(pickTask.getDocLineId());
                        stockChangeDto.setUserId(userId);
                        stockChangeDto.setStockId(stockBatchLoc.getId());
                        stockChangeDto = wmsStockFacade.subMainStock(stockChangeDto);
                        //增加拣货暂存库存
                        stockChangeDto = wmsStockFacade.addPickStock(stockChangeDto);
                        needSubQty = needSubQty.subtract(stockBatchLoc.getAvailableQty());
                    }
                }
                if (needSubQty.compareTo(BigDecimal.ZERO) > 0) {
                    throw new WmsServiceException("库存不足：商品编码:" + sku.getSkuCode() + "商品编条码:" + sku.getBarcode());
                }
            }
            //更新任务
            pickTask.setPickQty(param.getPickQty());
            pickTask.setTaskStatus(StockTaskStatusEnum.COMPLETED.getValue());
            if (!pickTaskService.updateById(pickTask)) {
                throw new WmsServiceException("更新拣货任务异常");
            }
        }
        //更新拣货单
        pickHeader.setPickStatus(PickStatusEnum.PICKED.getValue());
        pickHeader.setOpName(opName);
        pickHeader.setStartPickTime(new Date());
        pickHeader.setFinishPickTime(new Date());
        if (!pickHeaderService.updateById(pickHeader)) {
            throw new WmsServiceException("更新拣货单状态异常");
        }
        //更新波次
//        wave.setWaveStatus(WaveStatusEnum.COMPLETED.getValue());
//        if (!waveService.updateById(wave)) {
//            throw new WmsServiceException("更新波次状态异常");
//        }
    }

    @Transactional(rollbackFor = Exception.class)
    @Override
    public void pickDOPickTask(List<PickTaskDto> tasks, List<String> pointCodes, Long pickHeaderId, String opName, Long warehouseId, Integer userId) throws WmsServiceException {
        if (ListUtil.isNullOrEmpty(tasks)) {
            throw new WmsServiceException("任务参数缺失");
        }
        PickHeader pickHeader = pickHeaderService.getById(pickHeaderId);
        if (pickHeader == null) {
            throw new WmsServiceException("拣货单不存在");
        }
        if (!pickHeader.getDocType().equals(DocTypeEnum.DO.getValue())) {
            throw new WmsServiceException("拣货单类型不是DO");
        }
        if (!pickHeader.getPickStatus().equals(PickStatusEnum.PUBLISHED.getValue())) {
            throw new WmsServiceException("拣货单状态异常");
        }
        DeliveryOrderHeader orderHeader = deliveryOrderHeaderService.getById(pickHeader.getDocId());
        if (orderHeader == null) {
            throw new WmsServiceException("订单不存在");
        }
        if (!orderHeader.getOrderStatus().equals(DeliveryOrderStatusEnum.INIT.getValue()) &&
                !orderHeader.getOrderStatus().equals(DeliveryOrderStatusEnum.PICKING.getValue())) {
            throw new WmsServiceException("订单状态异常");
        }
        if (ListUtil.isNotEmpty(pointCodes)) {
            //绑定码托点数据
            for (String pointCode : pointCodes) {
                CodeHolderPoint point = Optional.ofNullable(codeHolderPointService.getByCode(pointCode, warehouseId)).orElseThrow(() -> new WmsServiceException("码托点不存在"));
                if (PointStatusEnum.STOP_USING.getValue().equals(point.getPointStatus())) {
                    throw new WmsServiceException("该码托点已停用");
                }
                if (PointStatusEnum.USING.getValue().equals(point.getPointStatus())) {
                    if (!orderHeader.getId().equals(point.getCurDocId())) {
                        throw new WmsServiceException("该码托点已被占用");
                    }
                }
                if (!point.getPointStatus().equals(PointStatusEnum.USING.getValue())) {
                    point.setPointStatus(PointStatusEnum.USING.getValue());
                    point.setCurDocId(orderHeader.getId());
                    point.setCurShopId(orderHeader.getShopId());
                    if (!codeHolderPointService.updateById(point)) {
                        throw new WmsServiceException("更新码托点异常");
                    }
                }
            }
        }
        //清除冗余数据
        List<DeliveryOrderBox> oldOrderBoxList = deliveryOrderBoxService.getByOrderHeaderId(orderHeader.getId());
        if (ListUtil.isNotEmpty(oldOrderBoxList)) {
            if (!deliveryOrderBoxService.removeByIds(oldOrderBoxList.stream().map(DeliveryOrderBox::getId).collect(Collectors.toList()))) {
                throw new WmsServiceException("清除历史数据异常");
            }
        }
        Map<Long, PickTaskDto> pickTaskMap = tasks.stream().collect(Collectors.toMap(PickTaskDto::getId, v -> v));
        List<PickTask> pickTasks = pickTaskService.getByDocOperId(pickHeader.getId());
        pickTasks.sort(Comparator.comparing(PickTask::getSkuId));
        for (PickTask pickTask : pickTasks) {
            PickTaskDto param = pickTaskMap.get(pickTask.getId());
            if (param == null) {
                throw new WmsServiceException("任务参数缺失");
            }
            if (pickTask.getTaskStatus().equals(StockTaskStatusEnum.COMPLETED.getValue())) {
                throw new WmsServiceException("该商品拣货任务已完成,无法继续拣货");
            }
            BigDecimal pickQty = param.getPickQty();
            if (pickQty.compareTo(BigDecimal.ZERO) < 0) {
                throw new WmsServiceException("拣货数不能为负数");
            }
            if (pickQty.compareTo(pickTask.getQty()) > 0) {
                throw new WmsServiceException("拣货数不能为大于订单发货数");
            }
            String boxCode = param.getBoxCode();
            Container box = null;
            if (StringUtils.isNotEmpty(boxCode)) {
                box = Optional.ofNullable(containerService.getByCode(boxCode, warehouseId)).orElseThrow(() -> new WmsServiceException("容器不存在"));
                if (ContainerStatusEnum.STOP_USING.getValue().equals(box.getContainerStatus())) {
                    throw new WmsServiceException("该容器已停用");
                }
                if (ContainerStatusEnum.USING.getValue().equals(box.getContainerStatus()) ||
                        ContainerStatusEnum.WAIT_RECEIVE.getValue().equals(box.getContainerStatus())) {
                    if (!orderHeader.getId().equals(box.getCurDocId())) {
                        throw new WmsServiceException("该容器已被占用");
                    }
                }
            }

            //更新拣货任务
            pickTask.setTaskStatus(StockTaskStatusEnum.COMPLETED.getValue());
            pickTask.setPickQty(param.getPickQty());
            pickTask.setReasonCode(param.getReasonCode());
            pickTask.setReasonDesc(param.getReasonDesc());
            if (!pickTaskService.updateById(pickTask)) {
                throw new WmsServiceException("更新拣货任务异常");
            }
            //回写发货数
            DeliveryOrderDetail orderDetail = deliveryOrderDetailService.getById(pickTask.getDocLineId());
            orderDetail.setSendQty(param.getPickQty().intValue());
            if (!deliveryOrderDetailService.updateById(orderDetail)) {
                throw new WmsServiceException("回写发货数异常");
            }
            //保存装箱信息
            DeliveryOrderBox orderBox = new DeliveryOrderBox();
            if (box != null) {
                orderBox.setBoxId(box.getId());
                orderBox.setBoxCode(boxCode);
            } else {
                orderBox.setBoxId(-1L);
                orderBox.setBoxCode("NONE");
            }
            orderBox.setBoxQty(param.getPickQty());
            orderBox.setOrderDetailId(pickTask.getDocLineId());
            orderBox.setOrderHeaderCode(orderHeader.getOrderCode());
            orderBox.setOrderHeaderId(orderHeader.getId());
            orderBox.setShopId(orderHeader.getShopId());
            orderBox.setWarehouseId(warehouseId);
            orderBox.setSkuId(pickTask.getSkuId());
            if (!deliveryOrderBoxService.save(orderBox)) {
                throw new WmsServiceException("保存装箱信息异常");
            }
            //更新容器状态
            if (box != null && !ContainerStatusEnum.USING.getValue().equals(box.getContainerStatus())) {
                box.setContainerStatus(ContainerStatusEnum.USING.getValue());
                box.setCurDocId(orderHeader.getId());
                box.setCurShopId(orderHeader.getShopId());
                if (!containerService.updateById(box)) {
                    throw new WmsServiceException("更新容器异常");
                }
            }

        }
        //扣减拣货库存
        subStockPick(pickTasks, warehouseId, userId);
        //更新拣货单状态
        pickHeader.setPickStatus(PickStatusEnum.PICKED.getValue());
        pickHeader.setStartPickTime(new Date());
        pickHeader.setFinishPickTime(new Date());
        pickHeader.setOpName(opName);
        if (!pickHeaderService.updateById(pickHeader)) {
            throw new WmsServiceException("更新拣货单状态异常");
        }
        //更新发货单状态
        orderHeader.setOrderStatus(DeliveryOrderStatusEnum.PICKED.getValue());
        if (!deliveryOrderHeaderService.updateById(orderHeader)) {
            throw new WmsServiceException("更新发货单状态异常");
        }


    }

    private void subStockPick(List<PickTask> pickTasks, Long warehouseId, Integer userId) throws WmsServiceException {
        for (PickTask pickTask : pickTasks) {
            Sku sku = skuService.getByIdForReal(pickTask.getSkuId());
            if (sku == null) {
                sku = new Sku();
                sku.setId(pickTask.getSkuId());
                sku.setBarcode("none-" + pickTask.getSkuId());
                sku.setSkuCode("none-" + pickTask.getSkuId());
            }
            BigDecimal needSubQty = pickTask.getPickQty();
            if (needSubQty.compareTo(BigDecimal.ZERO) == 0) {//未拣货
                continue;
            }
            List<StockPick> stockPickList = stockPickService.getBySkuId(pickTask.getSkuId());
            if (ListUtil.isNullOrEmpty(stockPickList)) {
                throw new WmsServiceException("拣货库存未找到该商品:商品编码:" + sku.getSkuCode() + "商品编条码:" + sku.getBarcode());
            }
            BigDecimal totalQty = stockPickList.stream().map(StockPick::getPickQty).reduce(BigDecimal::add).orElse(BigDecimal.ZERO);
            if (totalQty.compareTo(needSubQty) < 0) {
                throw new WmsServiceException("拣货库存不足：商品编码:" + sku.getSkuCode() + "商品编条码:" + sku.getBarcode());
            }
            for (StockPick stockPick : stockPickList) {
                if (needSubQty.compareTo(BigDecimal.ZERO) == 0) {//扣减结束
                    break;
                }
                if (stockPick.getPickQty().compareTo(needSubQty) >= 0) {
                    //扣减主库存
                    StockChangeDto stockChangeDto = new StockChangeDto();
                    stockChangeDto.setSkuId(pickTask.getSkuId());
                    stockChangeDto.setBatchId(stockPick.getBatchId());
//                    stockChangeDto.setToBatchId(WmsConstans.DEF_BATCH_ID);
                    stockChangeDto.setQty(needSubQty);
                    stockChangeDto.setLocId(stockPick.getLocId());
                    stockChangeDto.setWarehouseId(warehouseId);
                    stockChangeDto.setUserId(userId);
                    stockChangeDto.setStockId(stockPick.getId());
                    stockChangeDto = wmsStockFacade.subPickStock(stockChangeDto);
                    needSubQty = BigDecimal.ZERO;
                } else {
                    //扣减主库存
                    StockChangeDto stockChangeDto = new StockChangeDto();
                    stockChangeDto.setSkuId(pickTask.getSkuId());
                    stockChangeDto.setBatchId(stockPick.getBatchId());
//                    stockChangeDto.setToBatchId(WmsConstans.DEF_BATCH_ID);
                    stockChangeDto.setQty(stockPick.getPickQty());
                    stockChangeDto.setWarehouseId(warehouseId);
                    stockChangeDto.setUserId(userId);
                    stockChangeDto.setStockId(stockPick.getId());
                    stockChangeDto = wmsStockFacade.subPickStock(stockChangeDto);
                    needSubQty = needSubQty.subtract(stockPick.getPickQty());
                }
            }
            if (needSubQty.compareTo(BigDecimal.ZERO) > 0) {
                throw new WmsServiceException("拣货库存不足：商品编码:" + sku.getSkuCode() + "商品编条码:" + sku.getBarcode());
            }
        }
    }

    @Override
    public List<PickTaskDto> queryPickTask(Long pickHeaderId) throws WmsServiceException {
        List<PickTask> tasks = pickTaskService.getByDocOperId(pickHeaderId);
        List<PickTaskDto> result = new ArrayList<>();
        if (ListUtil.isNotEmpty(tasks)) {
            for (PickTask task : tasks) {
                PickTaskDto dto = new PickTaskDto();
                BeanUtils.copyProperties(task, dto);
                Sku sku = skuService.getById(task.getSkuId());
                if (sku != null) {
                    Spu spu = spuService.getById(sku.getSpuId());
                    dto.setBarCode(sku.getBarcode());
                    dto.setSkuCode(sku.getSkuCode());
                    dto.setSpuCode(spu.getSpuCode());
                    dto.setSpuName(spu.getSpuName());
                    dto.setDimensionValues(sku.getDimensionValues());
                }
                Location location = locationService.getById(task.getFmLocId());
                if (location != null) {
                    dto.setFmLocCode(location.getLocCode());
                }
                result.add(dto);
            }
        }
        return result;
    }

    @Override
    public IPage<DeliveryOrderHeaderDto> wrapperPickInfo(IPage<DeliveryOrderHeader> pageList) {
        IPage<DeliveryOrderHeaderDto> result = new Page<>();
        result.setCurrent(pageList.getCurrent());
        result.setPages(pageList.getPages());
        result.setSize(pageList.getSize());
        result.setTotal(pageList.getTotal());
        if (ListUtil.isNotEmpty(pageList.getRecords())) {
            List<DeliveryOrderHeaderDto> deliveryOrderHeaderDtos = new ArrayList<>();
            for (DeliveryOrderHeader orderHeader : pageList.getRecords()) {
                DeliveryOrderHeaderDto target = new DeliveryOrderHeaderDto();
                BeanUtils.copyProperties(orderHeader, target);
                Set<Long> boxIds = new HashSet<>();
                Long realCount = 0L;
                Long realBoxCount = 0L;
                Long realNoBoxCount = 0L;
                List<DeliveryOrderBox> deliveryOrderBoxes = deliveryOrderBoxService.getByOrderHeaderId(orderHeader.getId());
                for (DeliveryOrderBox deliveryOrderBox : deliveryOrderBoxes) {
                    long qty = deliveryOrderBox.getBoxQty().longValue();
                    realCount += qty;
                    if (-1L == deliveryOrderBox.getBoxId()) {
                        realNoBoxCount += qty;
                    } else {
                        boxIds.add(deliveryOrderBox.getBoxId());
                    }
                }
                realBoxCount = (long) boxIds.size();
                target.setSkuCount(realCount);
                target.setBoxCount(realBoxCount);
                target.setNoBoxCount(realNoBoxCount);
                deliveryOrderHeaderDtos.add(target);
            }
            result.setRecords(deliveryOrderHeaderDtos);
        }
        return result;
    }

    @Override
    public void freeContainer(Long containerId, Long warehouseId, Integer sysUserId) throws WmsServiceException {
        Container container = containerService.getById(containerId);
        if (container == null) {
            throw new WmsServiceException("容器不存在");
        }
        if (container.getCurDocId() != null) {
            DeliveryOrderHeader orderHeader = deliveryOrderHeaderService.getById(container.getCurDocId());
            if (orderHeader == null) {
                throw new WmsServiceException("订单不存在");
            }
            List<DeliveryOrderBox> orderBoxes = deliveryOrderBoxService.getByOrderHeaderId(orderHeader.getId());
            if (ListUtil.isNotEmpty(orderBoxes)) {
                for (DeliveryOrderBox orderBox : orderBoxes) {
                    if (container.getId().equals(orderBox.getBoxId())) {
                        DeliveryOrderBox deliveryOrderBox = deliveryOrderBoxService.getByOrderDetailIdAndBoxId(orderBox.getOrderDetailId(), -1L);
                        if (deliveryOrderBox == null) {
                            orderBox.setBoxId(-1L);
                            orderBox.setBoxCode("NONE");
                            deliveryOrderBoxService.updateById(orderBox);
                        } else {
                            deliveryOrderBox.setBoxQty(deliveryOrderBox.getBoxQty().add(orderBox.getBoxQty()));
                            deliveryOrderBoxService.updateById(deliveryOrderBox);
                            deliveryOrderBoxService.removeById(orderBox.getId());
                        }
                    }
                }
            }
        }
        container.setCurShopId(null);
        container.setCurDocId(null);
        container.setContainerStatus(ContainerStatusEnum.FREE.getValue());
        containerService.updateById(container);
    }
}
